package org.crh.appointment.impl;

import org.crh.appointment.AppointmentRecordService;
import org.crh.common.ScheduleService;
import org.crh.common.domain.AppointmentRecord;
import org.crh.common.response.ResponseData;
import org.crh.appointment.AppointmentService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.crh.appointment.domain.AppointmentReq;
import org.crh.common.response.impl.RuntimeResponse;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: RenHai Chen
 * @date: 2025/3/31 10:29
 */
@Service
public class AppointmentServiceImpl implements AppointmentService {

    @Autowired
    private AppointmentRecordService appointmentRecordService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ScheduleService scheduleService;

    @Autowired
    RedissonClient redissonClient;


    @GlobalTransactional // Seata全局事务
    @Override
    public ResponseEntity<ResponseData> grabAppointment(AppointmentReq appointmentReq) {
        // 分布式锁防止集群并发
        RLock lock = redissonClient.getLock("LOCK_APPOINT:" + appointmentReq.getSlotId());
        AppointmentRecord appointmentRecord = new AppointmentRecord();
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 1. Redis原子预减库存
                String key =String.valueOf(appointmentReq.getSlotId());
                RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
                String value = bucket.get();
                Long result = Long.valueOf(value);
                result = result-1;
                bucket.set(String.valueOf(result));
                if (result == -1) {
                    // 初始化库存
                    initStockToRedis(appointmentReq.getSlotId());
                    result = 1L;
                }

                if (result <= 0) {
                    return ResponseEntity.ok(new RuntimeResponse(500, "号源数量不足"));
                }

                // 2. 创建预约订单
                appointmentRecord = appointmentRecordService.createAppointmentRecord(appointmentReq);

                // 3. 发送延时消息（15分钟未支付）
                rocketMQTemplate.syncSendOrderly(
                        "ORDER_DELAY_TOPIC",
                        MessageBuilder.withPayload(appointmentRecord.getAppointmentId())
                                .setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "3")
                                .build(),
                        String.valueOf(appointmentRecord.getAppointmentId())
                );
            }
        }catch(Exception e){
            return ResponseEntity.ok(new RuntimeResponse(500, "创建预约订单异常:" + e.getMessage()));
        } finally {
            lock.unlock();
        }
        return ResponseEntity.ok(new RuntimeResponse(200, appointmentRecord));
    }


    private void initStockToRedis(Long slotId) {
        // 从数据库加载库存
        Integer dbStock = scheduleService.selectStock(slotId);
        String key =String.valueOf(slotId);
        RBucket<String> bucket = redissonClient.getBucket(key);
        bucket.set(String.valueOf(dbStock));
    }
}
